home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "ax25.h"
- #include "lapb.h"
- #include <ctype.h>
-
- static int16 ax25hash __ARGS((struct ax25_addr *s));
-
- struct ax25_cb *Ax25_cb[NHASH];
-
- /* Default AX.25 parameters */
- int32 T3init = 0; /* No keep-alive polling */
- int16 Maxframe = 1; /* Stop and wait */
- int16 N2 = 10; /* 10 retries */
- int16 Axwindow = 2048; /* 2K incoming text before RNR'ing */
- int16 Paclen = 256; /* 256-byte I fields */
- int16 Pthresh = 128; /* Send polls for packets larger than this */
- int32 Axirtt = 5000; /* Initial round trip estimate, ms */
- int16 Axversion = V1; /* Protocol version */
-
- /* Address hash function. Exclusive-ORs each byte, ignoring
- * such insignificant, annoying things as E and H bits
- */
- static int16
- ax25hash(s)
- struct ax25_addr *s;
- {
- register unsigned x;
- register int i;
- register char *cp;
-
- x = 0;
- cp = s->call;
- for(i=ALEN; i!=0; i--)
- x ^= *cp++;
- x &= 0xfe;
- x ^= s->ssid & SSID;
- return uchar(x) % NHASH;
- }
- /* Look up entry in hash table */
- struct ax25_cb *
- find_ax25(addr)
- register struct ax25_addr *addr;
- {
- int16 hashval;
- register struct ax25_cb *axp;
-
- /* Find appropriate hash chain */
- hashval = ax25hash(addr);
-
- /* Search hash chain */
- for(axp = Ax25_cb[hashval]; axp != NULLAX25; axp = axp->next){
- if(addreq(&axp->remote,addr)){
- return axp;
- }
- }
- return NULLAX25;
- }
-
- /* Remove address entry from hash table */
- void
- del_ax25(axp)
- register struct ax25_cb *axp;
- {
- int16 hashval;
-
- if(axp == NULLAX25)
- return;
- /* Remove from hash header list if first on chain */
- hashval = ax25hash(&axp->remote);
-
- /* Remove from chain list */
- if(axp->prev == NULLAX25)
- Ax25_cb[hashval] = axp->next;
- else
- axp->prev->next = axp->next;
- if(axp->next != NULLAX25)
- axp->next->prev = axp->prev;
-
- /* Timers should already be stopped, but just in case... */
- stop_timer(&axp->t1);
- stop_timer(&axp->t3);
-
- /* Free allocated resources */
- free_q(&axp->txq);
- free_q(&axp->rxasm);
- free_q(&axp->rxq);
- free((char *)axp);
- }
-
- /* Create an ax25 control block. Allocate a new structure, if necessary,
- * and fill it with all the defaults. The caller
- * is still responsible for filling in the reply address
- */
- struct ax25_cb *
- cr_ax25(addr)
- struct ax25_addr *addr;
- {
- register struct ax25_cb *axp;
- int16 hashval;
-
- if(addr == NULLAXADDR)
- return NULLAX25;
-
- if((axp = find_ax25(addr)) == NULLAX25){
- /* Not already in table; create an entry
- * and insert it at the head of the chain
- */
- /* Find appropriate hash chain */
- hashval = ax25hash(addr);
- axp = (struct ax25_cb *)calloc(1,sizeof(struct ax25_cb));
- if(axp == NULLAX25)
- return NULLAX25;
- /* Insert at beginning of chain */
- axp->next = Ax25_cb[hashval];
- if(axp->next != NULLAX25)
- axp->next->prev = axp;
- Ax25_cb[hashval] = axp;
- }
- axp->user = -1;
- axp->state = DISCONNECTED;
- axp->maxframe = Maxframe;
- axp->window = Axwindow;
- axp->paclen = Paclen;
- axp->proto = Axversion; /* Default, can be changed by other end */
- axp->pthresh = Pthresh;
- axp->n2 = N2;
- axp->srt = Axirtt / MSPTICK;
- axp->t1.start = 2*axp->srt;
- axp->t1.func = recover;
- axp->t1.arg = axp;
-
- axp->t3.start = T3init / MSPTICK;
- axp->t3.func = pollthem;
- axp->t3.arg = axp;
-
- /* Always to a receive and state upcall as default */
- axp->r_upcall = s_arcall;
- axp->s_upcall = s_ascall;
-
- return axp;
- }
-
- /*
- * setcall - convert callsign plus substation ID of the form
- * "KA9Q-0" to AX.25 (shifted) address format
- * Address extension bit is left clear
- * Return -1 on error, 0 if OK
- */
- int
- setcall(out,call)
- struct ax25_addr *out;
- char *call;
- {
- int csize;
- unsigned ssid;
- register int i;
- register char *cp,*dp;
- char c;
-
- if(out == (struct ax25_addr *)NULL || call == NULLCHAR || *call == '\0'){
- return -1;
- }
- /* Find dash, if any, separating callsign from ssid
- * Then compute length of callsign field and make sure
- * it isn't excessive
- */
- dp = strchr(call,'-');
- if(dp == NULLCHAR)
- csize = strlen(call);
- else
- csize = dp - call;
- if(csize > ALEN)
- return -1;
- /* Now find and convert ssid, if any */
- if(dp != NULLCHAR){
- dp++; /* skip dash */
- ssid = atoi(dp);
- if(ssid > 15)
- return -1;
- } else
- ssid = 0;
- /* Copy upper-case callsign, left shifted one bit */
- cp = out->call;
- for(i=0;i<csize;i++){
- c = *call++;
- if(islower(c))
- c = toupper(c);
- *cp++ = c << 1;
- }
- /* Pad with shifted spaces if necessary */
- for(;i<ALEN;i++)
- *cp++ = ' ' << 1;
-
- /* Insert substation ID field and set reserved bits */
- out->ssid = 0x60 | (ssid << 1);
- return 0;
- }
- /* Set an ARP table entry */
- int
- setpath(out,in)
- char *out; /* Target char array containing addresses in net form */
- char *in; /* Input array of tokenized callsigns in ASCII */
- {
- struct ax25_addr addr;
-
- setcall(&addr,in);
- out = putaxaddr(out,&addr);
- return 0;
- }
- int
- addreq(a,b)
- register struct ax25_addr *a,*b;
- {
- if(memcmp(a->call,b->call,ALEN) != 0)
- return 0;
- if((a->ssid & SSID) != (b->ssid & SSID))
- return 0;
- return 1;
- }
- /* Convert encoded AX.25 address to printable string */
- int
- pax25(e,addr)
- char *e;
- struct ax25_addr *addr;
- {
- register int i;
- char c,*cp;
-
- cp = addr->call;
- for(i=ALEN;i != 0;i--){
- c = (*cp++ >> 1) & 0x7f;
- if(c == ' ')
- break;
- *e++ = c;
- }
- if ((addr->ssid & SSID) != 0)
- sprintf(e,"-%d",(addr->ssid >> 1) & 0xf); /* ssid */
- else
- *e = 0;
- return 0;
- }
- /* Print an AX.25 address
- * Designed for use by ARP - arg is a char string
- */
- int
- psax25(e,addr)
- register char *e;
- register char *addr;
- {
- struct ax25_addr axaddr;
-
- /* Create local copy in host-format structure */
- addr = getaxaddr(&axaddr,addr);
-
- pax25(e,&axaddr);
- return 0;
- }
- char *
- getaxaddr(ap,cp)
- register struct ax25_addr *ap;
- register char *cp;
- {
- memcpy(ap->call,cp,ALEN);
- cp += ALEN;
- ap->ssid = *cp++;
- return cp;
- }
- char *
- putaxaddr(cp,ap)
- register char *cp;
- register struct ax25_addr *ap;
- {
- memcpy(cp,ap->call,ALEN);
- cp += ALEN;
- *cp++ = ap->ssid;
- return cp;
- }
-
- /* Convert a host-format AX.25 header into a mbuf ready for transmission */
- struct mbuf *
- htonax25(hdr,data)
- register struct ax25 *hdr;
- struct mbuf *data;
- {
- struct mbuf *bp;
- register char *cp;
- register int16 i;
-
- if(hdr == (struct ax25 *)NULL || hdr->ndigis > MAXDIGIS)
- return NULLBUF;
-
- /* Allocate space for return buffer */
- i = AXALEN * (2 + hdr->ndigis);
- if((bp = pushdown(data,i)) == NULLBUF)
- return NULLBUF;
-
- /* Now convert */
- cp = bp->data;
-
- hdr->dest.ssid &= ~E; /* Dest E-bit is always off */
- /* Encode command/response in C bits */
- switch(hdr->cmdrsp){
- case COMMAND:
- hdr->dest.ssid |= C;
- hdr->source.ssid &= ~C;
- break;
- case RESPONSE:
- hdr->dest.ssid &= ~C;
- hdr->source.ssid |= C;
- break;
- default:
- hdr->dest.ssid &= ~C;
- hdr->source.ssid &= ~C;
- break;
- }
- cp = putaxaddr(cp,&hdr->dest);
-
- /* Set E bit on source address if no digis */
- if(hdr->ndigis == 0){
- hdr->source.ssid |= E;
- putaxaddr(cp,&hdr->source);
- return bp;
- }
- hdr->source.ssid &= ~E;
- cp = putaxaddr(cp,&hdr->source);
-
- /* All but last digi get copied with E bit off */
- for(i=0; i < hdr->ndigis - 1; i++){
- hdr->digis[i].ssid &= ~E;
- cp = putaxaddr(cp,&hdr->digis[i]);
- }
- hdr->digis[i].ssid |= E;
- cp = putaxaddr(cp,&hdr->digis[i]);
- return bp;
- }
- /* Convert an AX.25 ARP table entry into a host format address structure
- * ready for use in transmitting a packet
- */
- int
- atohax25(hdr,hwaddr,source)
- register struct ax25 *hdr;
- register char *hwaddr;
- struct ax25_addr *source;
- {
- register struct ax25_addr *axp;
-
- hwaddr = getaxaddr(&hdr->dest,hwaddr); /* Destination address */
- ASSIGN(hdr->source,*source); /* Source address */
- if(hdr->dest.ssid & E){
- /* No digipeaters */
- hdr->ndigis = 0;
- hdr->dest.ssid &= ~E;
- hdr->source.ssid |= E;
- return 2;
- }
- hdr->source.ssid &= ~E;
- hdr->dest.ssid &= ~E;
- for(axp = hdr->digis; axp < &hdr->digis[MAXDIGIS]; axp++){
- hwaddr = getaxaddr(axp,hwaddr);
- if(axp->ssid & E){
- hdr->ndigis = axp - hdr->digis + 1;
- return hdr->ndigis;
- }
- }
- return -1;
- }
- /* Convert a network-format AX.25 header into a host format structure
- * Return -1 if error, number of addresses if OK
- */
- int
- ntohax25(hdr,bpp)
- register struct ax25 *hdr; /* Output structure */
- struct mbuf **bpp;
- {
- register struct ax25_addr *axp;
- char buf[AXALEN];
-
- if(pullup(bpp,buf,AXALEN) < AXALEN)
- return -1;
- getaxaddr(&hdr->dest,buf);
-
- if(pullup(bpp,buf,AXALEN) < AXALEN)
- return -1;
- getaxaddr(&hdr->source,buf);
-
- /* Process C bits to get command/response indication */
- if((hdr->source.ssid & C) == (hdr->dest.ssid & C))
- hdr->cmdrsp = UNKNOWN;
- else if(hdr->source.ssid & C)
- hdr->cmdrsp = RESPONSE;
- else
- hdr->cmdrsp = COMMAND;
-
- hdr->ndigis = 0;
- if(hdr->source.ssid & E)
- return 2; /* No digis */
-
- /* Process the digipeaters */
- for(axp = hdr->digis;axp < &hdr->digis[MAXDIGIS]; axp++){
- if(pullup(bpp,buf,AXALEN) < AXALEN){
- return -1;
- }
- getaxaddr(axp,buf);
- if(axp->ssid & E){ /* Last one */
- hdr->ndigis = axp - hdr->digis + 1;
- return hdr->ndigis + 2;
- }
- }
- return -1; /* Too many digis */
- }
-
- /* Figure out the frame type from the control field
- * This is done by masking out any sequence numbers and the
- * poll/final bit after determining the general class (I/S/U) of the frame
- */
- int16
- ftype(control)
- register char control;
- {
- if((control & 1) == 0) /* An I-frame is an I-frame... */
- return I;
- if(control & 2) /* U-frames use all except P/F bit for type */
- return(control & ~PF);
- else /* S-frames use low order 4 bits for type */
- return(control & 0xf);
- }
-